package org.ns.summer.data.mybatis;

import org.apache.ibatis.session.SqlSessionFactory;
import org.ns.summer.classpath.scan.prefix.PrefixTree;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.sql.DataSource;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;

public class DataSourceInvokeProxy implements InvocationHandler {
    private static Logger log = LoggerFactory.getLogger(DataSourceInvokeProxy.class);
    private SqlSessionFactory sqlSessionFactory;
    private DataSource dataSource;

    public DataSourceInvokeProxy(SqlSessionFactory sqlSessionFactory) {
        this.sqlSessionFactory = sqlSessionFactory;
        this.dataSource = sqlSessionFactory.getConfiguration().getEnvironment().getDataSource();
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        MybatisTransactionManage manage = MybatisTransactionManage.get();
        if (manage == null) {
            return method.invoke(dataSource, args);
        }
        if (method.getName().equals("getConnection")) {
            if (args.length == 0) {
                Connection connection = manage.openSession(sqlSessionFactory).getConnection();
                log.debug("[事务] 数据源获取连接！");
                return Proxy.newProxyInstance(getClass().getClassLoader(),
                        new Class[]{Connection.class}, new ConnectionTransactionProxy(connection));
            }
        }

        return method.invoke(dataSource, args);
    }
    
    public static class ConnectionTransactionProxy implements InvocationHandler {
        private Connection connection;
        private PrefixTree prefixTree = PrefixTree.create("close", "commit", "rollback", "setAutoCommit");
        private static Logger log = LoggerFactory.getLogger(ConnectionTransactionProxy.class);

        public ConnectionTransactionProxy(Connection connection) {
            this.connection = connection;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            String name = method.getName();
            if (prefixTree.match(name)) {
                log.warn("不允许使用此方法：" + name);
                return null;
            }
            return method.invoke(connection, args);
        }
    }
}
